package gu.rpc.thrift;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;

/**
 * 数据类型处理工具
 * @author guyadong
 *
 */
public class TypeUtils {
	/** 动态注释 annotation类名 */
	private static final String TARGET_TYPE_NAME="TargetType";
	/** 动态注释的值域名 */
	private static final String TARGET_TYPE_VALUE_NAME="value";
	/** 验证动态注释类的值 */
	private static final String AUTHEN_VALUE ="gu";
	/** 验证动态注释类的域名 */
	private static final String AUTHEN_FIELD_NAME="AUTHENTICATION";
	/** DAO类型包名 */
	private static final ThreadLocal<String> packagePrefixOfDao = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}}; 
	/** thrift生成的client端代码的包名 */
	private static final ThreadLocal<String> packagePrefixOfThrift = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}}; 	
	private static final ThreadLocal<String> replacePackageOfDAO = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}}; 
	/** 是否只返回RawType,参见 {@link #asJavaType(Type)} */
	private static final ThreadLocal<Boolean> rawTypeOnly = new ThreadLocal<Boolean>(){
		@Override
		protected Boolean initialValue() {
			return false;
		}}; 
	private static final ThreadLocal<Class<?>> daoType = new ThreadLocal<Class<?>>();
	private static final ThreadLocal<String> convertVar = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	private static final ThreadLocal<String> toBytesMethodPrefix = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	private static final ThreadLocal<String> toBufferMethodPrefix = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	private static final ThreadLocal<String> toLongMethodPrefix = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	private static final ThreadLocal<String> toDateMethodPrefix = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	private static final ThreadLocal<String> checkNotNullElementPrefix = new ThreadLocal<String>(){
		@Override
		protected String initialValue() {
			return "";
		}};
	public String asTypeString(Type type){
		if(byte[].class == type || java.nio.ByteBuffer.class == type){
			return "byte[]";
		}else if(java.nio.ByteBuffer.class == type){
			return "byte[]";
		}
		return type.toString();		
	}
	public Class<?> getElementClassOfArray(Class<?> clazz) {
		return clazz.isArray() ? getElementClassOfArray(clazz.getComponentType()) : clazz;
	}
	public Type getElementTypeOfArray(Type type) {
		return type instanceof Class<?> ? getElementClassOfArray((Class<?>)type):type;
	}
	public int getDimensionOfArray(Class<?> clazz) {
		return clazz.isArray() ?getDimensionOfArray(clazz.getComponentType())+1:0;
	}
	public Type getElementTypeOfList(Type type) {
		return isList(type) ? getElementTypeOfList(((ParameterizedType)type).getActualTypeArguments()[0]):type;
	}
	public int getDimensionOfList(Type type) {
		return isList(type) ? getDimensionOfList(((ParameterizedType)type).getActualTypeArguments()[0])+1:0;
	}
	public Type mapType(Type type){
		if(java.nio.ByteBuffer.class == type){
			return byte[].class;
		}
		if(type instanceof ParameterizedType){
			Type rawType = ((ParameterizedType)type).getRawType();
			if(rawType instanceof Class<?> && java.util.Map.class.isAssignableFrom((Class<?>)rawType)){
				Type[] typeArg = ((ParameterizedType)type).getActualTypeArguments();
				if(typeArg[0] == byte[].class){
					
				}
			}
		}
		return type;		
	}
	private static boolean isIgnorePackage(Class<?> type){
		if(null == type.getPackage()){
			return false;
		}
		String pkg = type.getPackage().getName();
		if("java.lang".equals(pkg)){
			return true;
		}
		if("java.util".equals(pkg)){
			return true;
		}
		if(java.nio.ByteBuffer.class == type){
			return true;
		}
		return false;
	}
	public boolean isDao(Type type){
		daoType.set(null);
		if(type instanceof Class<?>){
			Class<?> clazz = (Class<?>)type;
			if(null != clazz.getPackage()){
				String pkg = clazz.getPackage().getName();
				String prefix = packagePrefixOfDao.get();
				if(null != prefix && 0 == pkg.indexOf(prefix)){
					daoType.set(clazz);
				}
			}
		}
		return null != daoType.get();
	}
	public String asJavaType(Type type,String prefix){
		if(null != prefix){
			replacePackageOfDAO.set(prefix);
		}
		try{
			return  asJavaType(type);
		}finally{
			replacePackageOfDAO.set("");
		}
	}
	public String asJavaType(Type type){
		checkNotNull(type);
		if(Boolean.TRUE == rawTypeOnly.get()){
			type = TypeToken.of(type).getRawType();
		}
		if(type instanceof Class<?>){
			Class<?> clazz = (Class<?>)type;
			if(clazz.isArray()){
				return asJavaType(clazz.getComponentType())+"[]";
			}else if(isIgnorePackage(clazz) || clazz.isPrimitive()){ // Java 内置数据类型
				return clazz.getSimpleName();
			}else if(isDao(clazz)){ // 数据库访问对象
				if(replacePackageOfDAO.get().isEmpty()){
					return clazz.getSimpleName();
				}else{
					return replacePackageOfDAO.get() +"." + clazz.getSimpleName();
				}
			}else // 非数据库访问对象的自定义类型 
				if(packagePrefixOfThrift.get().isEmpty()){ 
				return clazz.getName();
			}else{
				return packagePrefixOfThrift.get() +"." + clazz.getSimpleName();
			}
		}else if(type instanceof ParameterizedType){
			return asJavaType((ParameterizedType)type);
		}/*else if(type instanceof GenericArrayType){
			System.out.println("GenericArrayType " +  type.toString());
			return asJavaType(((GenericArrayType)type).getGenericComponentType()) + "[]";
		}*/else{
			return type.toString();
		}
	}
	private String asJavaType(ParameterizedType parameterizedType) {
		StringBuilder stringBuilder = new StringBuilder();
		Type ownerType = parameterizedType.getOwnerType();
		Type rawType = parameterizedType.getRawType();
		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
		if (ownerType != null) {			
			stringBuilder.append(asJavaType(ownerType));
			stringBuilder.append(".");
			if (ownerType instanceof ParameterizedType) {
				stringBuilder.append(asJavaType(rawType)
						.replace((asJavaType(((ParameterizedType) ownerType).getRawType())) + "$", ""));
			} else {
				stringBuilder.append(asJavaType(rawType));
			}
		} else {
			stringBuilder.append(asJavaType(rawType));
		}
		if (actualTypeArguments != null && actualTypeArguments.length > 0) {
			stringBuilder.append("<");
			boolean bl = true;
			for (Type type : actualTypeArguments) {
				if (!bl) {
					stringBuilder.append(", ");
				}
				stringBuilder.append(asJavaType(type));
				bl = false;
			}
			stringBuilder.append(">");
		}
		return stringBuilder.toString();
	}
	public Class<?> getRawType(Type type){
		return TypeToken.of(type).getRawType();
	}
	private static Class<?> findClassInTypeArgument(Type type,Function<Type,Class<?>> checker){
		if(type instanceof ParameterizedType){
			Type[] typeArgs = ((ParameterizedType)type).getActualTypeArguments();
			for(Type arg:typeArgs){
				Class<?> clazz = checker.apply(arg);
				if(null != clazz){
					return clazz;
				}
			}
		}
		return null;
	}
	private static boolean hasTypeArgument(Type type,Predicate<Type> checker){
		if(type instanceof ParameterizedType){
			Type[] typeArgs = ((ParameterizedType)type).getActualTypeArguments();
			for(Type arg:typeArgs){
				if(checker.apply(arg)){
					return true;
				}
			}
		}
		return false;
	}
	private boolean hasDaoTypeArgument(Type type){
		return hasTypeArgument(type,new Predicate<Type>(){
			@Override
			public boolean apply(Type input) {
				return isDao(input);
			}});
	}
	private boolean hasByteBufferTypeArgument(Type type){
		return hasTypeArgument(type,new Predicate<Type>(){
			@Override
			public boolean apply(Type input) {
				return isByteBuffer(input);
			}});
	}
	private boolean hasDateTypeArgument(Type type){
		return hasTypeArgument(type,new Predicate<Type>(){
			@Override
			public boolean apply(Type input) {
				return isDate(input);
			}});
	}
	private boolean hasLongTypeArgument(Type type){
		return hasTypeArgument(type,new Predicate<Type>(){
			@Override
			public boolean apply(Type input) {
				return isLong(input);
			}});
	}
	public boolean isMap(Type type){
		return java.util.Map.class.isAssignableFrom(getRawType(type));
	}
	public boolean isDaoMap(Type type){
		return isMap(type) && hasDaoTypeArgument(type);
	}
	public boolean isByteBufferMap(Type type){
		return isMap(type) && hasByteBufferTypeArgument(type);
	}
	public boolean isDateMap(Type type){
		return isMap(type) && hasDateTypeArgument(type);
	}
	public boolean isLongMap(Type type){
		return isMap(type) && hasLongTypeArgument(type);
	}
	public boolean isMapOfDaoKey(Type type){
		return isMap(type) && isDao(((ParameterizedType)type).getActualTypeArguments()[0]);
	}
	public boolean isMapOfDaoValue(Type type){
		return isMap(type) && isDao(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfDaoKeyValue(Type type){
		return isMap(type) 
				&& isDao(((ParameterizedType)type).getActualTypeArguments()[0])
				&& isDao(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfByteBufferKey(Type type){
		return isMap(type) && isByteBuffer(((ParameterizedType)type).getActualTypeArguments()[0]);
	}
	public boolean isMapOfByteBufferValue(Type type){
		return isMap(type) && isByteBuffer(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfByteBufferKeyValue(Type type){
		return isMap(type) 
				&& isByteBuffer(((ParameterizedType)type).getActualTypeArguments()[0])
				&& isByteBuffer(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfDateKey(Type type){
		return isMap(type) && isDate(((ParameterizedType)type).getActualTypeArguments()[0]);
	}
	public boolean isMapOfDateValue(Type type){
		return isMap(type) && isDate(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfDateKeyValue(Type type){
		return isMap(type) 
				&& isDate(((ParameterizedType)type).getActualTypeArguments()[0])
				&& isDate(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfLongKey(Type type){
		return isMap(type) && isLong(((ParameterizedType)type).getActualTypeArguments()[0]);
	}
	public boolean isMapOfLongValue(Type type){
		return isMap(type) && isLong(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isMapOfLongKeyValue(Type type){
		return isMap(type) 
				&& isLong(((ParameterizedType)type).getActualTypeArguments()[0])
				&& isLong(((ParameterizedType)type).getActualTypeArguments()[1]);
	}
	public boolean isList(Type type){
		return java.util.List.class.isAssignableFrom(getRawType(type));
	}
	public boolean isDaoList(Type type){
		return isList(type) && hasDaoTypeArgument(type);
	}
	public boolean isByteBufferList(Type type){
		return isList(type) && hasByteBufferTypeArgument(type);
	}
	public boolean isDateList(Type type){
		return isList(type) && hasDateTypeArgument(type);
	}
	public boolean isLongList(Type type){
		return isList(type) && hasLongTypeArgument(type);
	}
	public boolean isSet(Type type){
		return java.util.List.class.isAssignableFrom(getRawType(type));
	}
	public boolean isDaoSet(Type type){
		return isSet(type) && hasDaoTypeArgument(type);
	}
	public boolean isByteBufferSet(Type type){
		return isSet(type) && hasByteBufferTypeArgument(type);
	}
	public boolean isDateSet(Type type){
		return isSet(type) && hasDateTypeArgument(type);
	}
	public boolean isLongSet(Type type){
		return isSet(type) && hasLongTypeArgument(type);
	}
	public boolean isCollection(Type type){
		return java.util.Collection.class.isAssignableFrom(getRawType(type));
	}
	public Type elementTypeOfCollection(Type type){
		checkArgument(isCollection(type),"type is not collection");
		return ((ParameterizedType)type).getActualTypeArguments()[0];
	}
	public boolean isDaoCollection(Type type){
		return isCollection(type) && hasDaoTypeArgument(type);
	}
	public boolean isByteBufferCollection(Type type){
		return isCollection(type) && hasByteBufferTypeArgument(type);
	}
	public boolean isDateCollection(Type type){
		return isCollection(type) && hasDateTypeArgument(type);
	}
	public boolean isLongCollection(Type type){
		return isCollection(type) && hasLongTypeArgument(type);
	}
	public boolean isArray(Type type){
		return TypeToken.of(type).isArray();		
	}
	public boolean isDaoArray(Type type){
		TypeToken<?> typeToken = TypeToken.of(type);
		return typeToken.isArray() && isDao(typeToken.getComponentType().getType());
	}
	public boolean isByteBufferArray(Type type){
		TypeToken<?> typeToken = TypeToken.of(type);
		return typeToken.isArray() && isByteBuffer(typeToken.getComponentType().getType());
	}
	public boolean isDateArray(Type type){
		TypeToken<?> typeToken = TypeToken.of(type);
		return typeToken.isArray() && isDate(typeToken.getComponentType().getType());
	}
	public boolean isLongArray(Type type){
		TypeToken<?> typeToken = TypeToken.of(type);
		return typeToken.isArray() && isLong(typeToken.getComponentType().getType());
	}
	public boolean isTypeOfDao(Type type){
		return isDao(type) || isDaoMap(type) || isDaoCollection(type) || isDaoArray(type);
	}
	public boolean isTypeOfByteBuffer(Type type){
		return isByteBuffer(type) || isByteBufferMap(type) || isByteBufferCollection(type) || isByteBufferArray(type);
	}
	public boolean isTypeOfDate(Type type){
		return isDate(type) || isDateMap(type) || isDateCollection(type) || isDateArray(type);
	}
	public boolean isTypeOfLong(Type type){
		return isLong(type) || isLongMap(type) || isLongCollection(type) || isLongArray(type);
	}
	public boolean isByteBuffer(Type type){
		return java.nio.ByteBuffer.class == type;
	}
	public boolean isBinary(Type type){
		return isByteBuffer(type) || byte[].class == type;
	}
	public boolean isDate(Type type){
		try{
			return (java.util.Date.class.isAssignableFrom((Class<?>) type));
		}catch(Exception e){
			return false;
		}
	}
	public boolean isLong(Type type){
		return type == Long.class || type == long.class;
	}
	public boolean isPrimitiveList(Type type, AtomicInteger dimension){
		return null  != getPrimitiveFromList(type,dimension);
	}
	public boolean isPrimitiveList(Type type){
		return isPrimitiveList(type,null);
	}
	public Type getCollectionElementType(Type type) {
		if(null == type){
			return null;
		}
		TypeToken<?> typeToken = TypeToken.of(type);
		if( java.util.Collection.class.isAssignableFrom(typeToken.getRawType())){
			return TypeToken.of(((ParameterizedType)typeToken.getType()).getActualTypeArguments()[0]).getType();
		}
		return null;
	}
	private Class<?> getPrimitiveFromList(Type type, AtomicInteger dimension){
		if(null == type){
			return null;
		}
		TypeToken<?> typeToken = TypeToken.of(type);
		if( java.util.List.class.isAssignableFrom(typeToken.getRawType())){
			if(null != dimension){
				dimension.incrementAndGet();
			}
			TypeToken<?> elementType = TypeToken.of(((ParameterizedType)typeToken.getType()).getActualTypeArguments()[0]);
			Class<?> primitiveType = getPrimitiveFromList(elementType.getType(), dimension);
			if(null != primitiveType){
				return primitiveType;
			}
			TypeToken<?> unwrapType = elementType.unwrap();
			if(unwrapType.isPrimitive()){
				return (Class<?>) unwrapType.getType();
			}
		}
		return null;
	}
	public Type toPrimitiveArray(Type type){
		AtomicInteger dimensionCount = new AtomicInteger(0);
		Class<?> primitiveType = getPrimitiveFromList(type,dimensionCount);
		if(null != primitiveType && primitiveType != Void.TYPE){
			int[] dim = new int[dimensionCount.get()];
			Arrays.fill(dim, 0);
			return Array.newInstance(primitiveType, dim).getClass();
		}
		return type;
	}
	public void setPackagePrefixOfDao(String prefix){
		if(null != prefix){
			packagePrefixOfDao.set(prefix);
		}
	}
	public void setPackagePrefixOfThrift(String prefix){
		if(null != prefix){
			packagePrefixOfThrift.set(prefix);
		}
	}
	public void setConvertVar(String prefix){
		convertVar.set(prefix);
	}
	public void setToBytesMethodPrefix(String prefix){
		toBytesMethodPrefix.set(prefix);
	}
	public void setToBufferMethodPrefix(String prefix){
		toBufferMethodPrefix.set(prefix);
	}
	public void setToLongMethodPrefix(String prefix){
		toLongMethodPrefix.set(prefix);
	}
	public void setToDateMethodPrefix(String prefix){
		toDateMethodPrefix.set(prefix);
	}
	public void setCheckNotNullElementPrefix(String prefix){
		checkNotNullElementPrefix.set(prefix);
	}
	public Type toPrimitive(Type type){
		if(isByteBuffer(type)){
			return byte[].class;
		}
		TypeToken<?> typeToken = TypeToken.of(type);
		return typeToken.unwrap().getType();
	}
	public Type toCallType(Type type){
		if(isByteBuffer(type)){
			return byte[].class;
		}
		return type;
	}
	public Type wrap(Type type){
		return TypeToken.of(type).wrap().getType();
	}
	public boolean isVoid(Type type){
		return Void.TYPE == type;
	}
	/**
	 * 生成DAO类型转换语句
	 * @param type
	 * @param var
	 * @param toRight
	 * @return
	 */
	public String castStatementOfDao(Type type,String var,boolean toRight){
		String method=(toRight?"toRight":"fromRight");
		if(isTypeOfDao(type)){
			if(isDaoMap(type)){
				if(isMapOfDaoKeyValue(type)){
					method += "";
				}else if(isMapOfDaoKey(type)){
					method += "Key";
				}else if(isMapOfDaoValue(type)){
					method += "Value";
				}
			}
			String cv = convertVar.get().replace("$bean$", daoType.get().getSimpleName());
			String rs = convertVar.get().replace("$bean$", "");
			if(rs.equals(rs.toUpperCase())){
				cv = cv.toUpperCase();
			}
			return String.format("%s.%s(%s)", cv,method,var);
		}else{
			return var;
		}
	}
	/**
	 * 生成binary类型转换语句
	 * @param type
	 * @param var
	 * @param toRight
	 * @return
	 */
	public String castStatementOfByteBuffer(Type type,String var, boolean toRight){
		String suffix="";
		if(isTypeOfByteBuffer(type)){
			if(isByteBufferMap(type)){
				if(isMapOfByteBufferKeyValue(type)){
					//
				}else if(isMapOfByteBufferKey(type)){
					suffix += "Key";
				}else if(isMapOfByteBufferValue(type)){
					suffix += "Value";
				}
			}
			if(toRight)
				return String.format("%s%s(%s)", toBytesMethodPrefix.get(),
						suffix,var);
			else
				return String.format("%s%s(%s)", toBufferMethodPrefix.get(),
						suffix,var);
		}else{
			return var;
		}
	}
	public String castStatementOfByteBuffer(Type type,String var){
		return castStatementOfByteBuffer(type,var,true);
	}	
	/** 生成日期类型转换语句
	 * @param type
	 * @param var
	 * @param toRight
	 * @return
	 */
	public String castStatementOfDate(Type type,String var,boolean toRight){
		String suffix="";
		if(isTypeOfDate(type)){
			Class<?> dateType = isDate(type)? (Class<?>)type :findClassInTypeArgument(type,new Function<Type,Class<?>>(){
				@Override
				public Class<?> apply(Type input) {
					return (Class<?>) (isDate(input)? input:null);
				}});
			if(isDateMap(type)){
				if(isMapOfDateKeyValue(type)){
					//
				}else if(isMapOfDateKey(type)){
					suffix += "Key";
				}else if(isMapOfDateValue(type)){
					suffix += "Value";
				}
			}
			return String.format("%s%s(%s,%s.class)", 
					toRight?toLongMethodPrefix.get():toDateMethodPrefix.get(),
					suffix,var,asJavaType(dateType));
		}else{
			return var;
		}
	}
	public String castStatement(Type type,String var,boolean toRight){
		String statement = castStatementOfByteBuffer(type,
				castStatementOfDao(type,
						castStatementOfDate(type, var, toRight),toRight), toRight);
		return (isDaoList(type) && !toRight)
				? new StringBuffer().append(asJavaType(elementTypeOfCollection(type)))
						.append(".replaceNullInstance(")
						.append(statement)
						.append(")")
						.toString()
				: statement; 
	}
	/** 生成向右的类型转换语句 */
	public String toRight(Type type,String var,Boolean isGeneric){
		if(isCollection(type)){
			// 检查是否有为null元素的调用
			var = String.format("%s(%s)", checkNotNullElementPrefix.get(),var);			
		}
		if(Boolean.TRUE.equals(isGeneric) && isBinary(type)){
			return castStatementOfByteBuffer(type,var, true);
		}else{
			return castStatement(toPrimitive(type),var,true);
		}
	}
	/** 生成向左的类型转换语句 */
	public String fromRight(Type type,String var){
		return castStatement(toPrimitive(type),var,false);
	}
	/**  判断指定的类型是否需要fromRight转换 */
	public boolean needFromRight(Type type){
		String var ="var";
		return !var.equals(fromRight(type,var));
	}
	/**
	 * 将{@code type}类型转为swift调用的参数声明类型文本<br>
	 * {@link java.nio.ByteBuffer}转为{@code byte[]},其他类型原样输出
	 * @param type
	 * @param isGeneric 为{@code true}时返回"Object"
	 * @return
	 */
	public String asSwiftDeclareType(Type type,Boolean isGeneric){
		if(Boolean.TRUE.equals(isGeneric) && isBinary(type)){
			return "Object";
		}else{
			return asJavaType(isByteBuffer(type) ? byte[].class : type);
		}
	}
	public boolean existsBinaryParam(Method method){
		if(null == method){
			return false;
		}
		for(Class<?> type:method.getParameterTypes()){
			if(isBinary(type)){
				return true;
			}
		}
		return false;
	}
	/**
	 * 根据{@code returnType}生成返回类型
	 * @param returnType
	 * @param wrap
	 * @return
	 */
	public String asReturnType(Type returnType,boolean wrap){
		return asJavaType(toCallType(wrap?wrap(returnType):returnType));
	}
	/**
	 * 根据{@code thriftType}生成swift类型
	 * @param thriftType
	 * @param prefix
	 * @return
	 */
	public String asSwiftType(Type thriftType,String prefix){
		return asJavaType(toPrimitive(thriftType),prefix);
	}
	
	private boolean isAuthentication(Class<? extends Annotation> annotationType){
		try {
			Field field = annotationType.getField(AUTHEN_FIELD_NAME);
			return AUTHEN_VALUE.equals(field.get(null));
		} catch (Exception e) {
			return false;
		}
	}
	/**
	 * 验证是否为TargetType注释
	 * @param ann
	 * @return
	 */
	private boolean isTargeType(Annotation ann){
		Class<? extends Annotation> annotationType = ann.annotationType();
		return (TARGET_TYPE_NAME.endsWith(annotationType.getSimpleName())
				&&isAuthentication(annotationType));
	}
	/**
	 * 查找 TargetType注释
	 * @param annotations
	 * @return
	 */
	private Annotation findTargetTypeAnnotation(Annotation[] annotations){
		for(Annotation ann:annotations){
			if(isTargeType(ann)){
				return ann;
			}
		}
		return null;
	}
	/**
	 * 返回 {@link Annotation}中的所有值
	 * @param annotation
	 * @return
	 */
	private Map<String,Object> valuesOfAnnotation(Annotation annotation){
		try {
			HashMap<String, Object> map = Maps.<String,Object>newHashMap();
			if(null != annotation){
				Class<? extends Annotation> annotationType = annotation.annotationType();
				for(Method method:annotationType.getDeclaredMethods()){
					map.put(method.getName(), method.invoke(annotation));
				}
			}
			return map;
		} catch(RuntimeException e){
			throw e;
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 查找TargetType并返回TargetType定义的类
	 * @param anns
	 * @return
	 * @see #findTargetTypeAnnotation(Annotation[])
	 */
	private Class<?> findTargetType(Annotation[] anns){
		Annotation found = findTargetTypeAnnotation(anns);
		try{
			return  (Class<?>) valuesOfAnnotation(found).get(TARGET_TYPE_VALUE_NAME);
		}catch(ClassCastException e ){
			throw new IllegalStateException("can't get Class from " + found.annotationType().getName());
		}
	}
	/** 
	 * @return 返回method的targetTypeClass,(如果没有则返回null) 
	 */
	private Class<?> targetTypeOfReturn(Method method){
		checkNotNull(method,"method is null");	
		return findTargetType(method.getAnnotations());
	}
	/** 返回method的所有参数的targetTypeClass,(如果没有则对应数组元素为null) */
	public Class<?>[] targetTypeOfParameters(Method method){
		checkNotNull(method,"method is null");	
		Annotation[][] annotations = method.getParameterAnnotations();
		Class<?>[] parameterTypes = new Class<?>[annotations.length];
		for(int i=0;i<parameterTypes.length;++i){
			parameterTypes[i]= findTargetType(annotations[i]);
		}
		return parameterTypes;
	}
	/** 
	 * 对{@link ParameterizedType}类型的{@code originalType}，将其中满足TargetType类型转换的类型(目前只支持Long --Date)参数替换成{@code targetType}<br>
	 * 如果 {@code originalType}等于{@code targetType}则返回 {@code targetType}<br>
	 * 如果 {@code targetType}为{@code null}或{@code originalType}
	 * 不是{@link ParameterizedType}则返回{@code originalType}
	 * @return 返回新的{@link ParameterizedType} 
	 */
	private  Type transformTargetType(Type originalType,Class<?>targetType){
		checkNotNull(originalType,"originalType is null");
		if(null == targetType){
			return originalType;
		}
		if(java.util.Date.class.isAssignableFrom(targetType)){
			if(isLong(originalType)){
				return targetType;
			}
			if(isTypeOfLong(originalType)){
				return new ParameterizedTypeImpl((ParameterizedType) originalType).transform(Long.class, targetType);
			}
		}
		return originalType;
	}

	/**
	 * 返回thrift方法的实际参数类型列表,完成targetType替换
	 * @param method
	 * @param thriftSignture
	 * @return
	 */
	private LinkedHashMap<String, Type> signtureOfMethod(Method method,LinkedHashMap<String, Type>thriftSignture){
		checkNotNull(method,"method is null");
		checkNotNull(thriftSignture,"thriftSignture is null");
		Class<?>[] targetTypes = targetTypeOfParameters(method);
		checkArgument(targetTypes.length == thriftSignture.size());
		int count = 0;
		for(Entry<String, Type> entry:thriftSignture.entrySet()){
			entry.setValue(transformTargetType(entry.getValue(),targetTypes[count]));
			++count;
		}
		return thriftSignture;		
	}
	/**
	 * 根据{@link Method}的TargetType计算实际的返回类型
	 * @param method
	 * @param thriftReturnType
	 * @return 如果 {@code method}没有定义TargetType,则返回{@code thriftReturnType}
	 */
	public Type returnTypeOfMethod(Method method,Type thriftReturnType){
		checkNotNull(method,"method is null");
		checkNotNull(thriftReturnType,"thriftReturnType is null");
		Class<?> targetType = targetTypeOfReturn(method);
		Class<?> methodReturn = method.getReturnType();
		// 如果thriftReturnType 是泛型,则返回类型计算以thriftReturnType准，
		// 否则以method的实际返回类型为准 
		return transformTargetType(
				thriftReturnType instanceof ParameterizedType
					? thriftReturnType
					: methodReturn,
				targetType);
	}
	/**
	 * 计算方法调用的参数字符串
	 * @param method
	 * @param thriftSignture
	 * @param isGeneric 是否为泛型
	 * @param withType 输出类型
	 * @param withName 输出变量名
	 * @param separator
	 * @param rawTypeOnly 只输出rawType
	 * @param toRight 是否生成toRight类型转换语句
	 * @param indent 多行缩进字符串
	 * @param withFinal 是否为final
	 * @return
	 */
	protected String formateParam(Method method,LinkedHashMap<String, Type>thriftSignture,
			Boolean isGeneric,Boolean withType,Boolean withName, String separator,Boolean rawTypeOnly, 
			Boolean toRight, String indent, Boolean withFinal){
		StringBuffer buffer = new StringBuffer();
		LinkedHashMap<String, Type> parameterTypes = signtureOfMethod(method, thriftSignture);
		int count = 0;
		try{
			TypeUtils.rawTypeOnly.set(rawTypeOnly);
			int paramNum = parameterTypes.size();
			for(Entry<String, Type> entry:parameterTypes.entrySet()){
				++count;
				if(null !=indent && paramNum>1){
					buffer.append(indent);
				}
				if(Boolean.TRUE.equals(withType)){
					if(Boolean.TRUE.equals(withFinal)){
						buffer.append("final ");
					}
					buffer.append(asSwiftDeclareType(entry.getValue(), isGeneric));
					if(Boolean.TRUE.equals(withName)){
						buffer.append(' ');
					}
				}				
				if(Boolean.TRUE.equals(withName)){
					if(Boolean.TRUE.equals(toRight)){
						buffer.append(toRight(entry.getValue(),entry.getKey(),isGeneric));
					}else{
						buffer.append(entry.getKey());
					}
				}
				if(count<paramNum){
					buffer.append(null ==separator?"":separator);
				}
			}
			return buffer.toString();
		}finally{
			TypeUtils.rawTypeOnly.set(false);
		}
	}
	static enum SignParam{
		/** 是否泛型 */
		isGeneric,withType,withName,separator,rawTypeOnly,toRight,indent,withFinal;
		private static final Map<SignParam, Object> DEFAULT_PARAM =
				Collections.unmodifiableMap(new EnumMap<SignParam, Object>(SignParam.class){
					private static final long serialVersionUID = 1L;{
						put(isGeneric,false);
						put(withType,false);
						put(withName,false);
						put(separator,",");
						put(rawTypeOnly,false);
						put(toRight,false);
						put(indent,"");
						put(withFinal,false);
					}});
		static final EnumMap<SignParam, Object> defaultParameter(){
			return new EnumMap<SignParam, Object>(SignParam.DEFAULT_PARAM);
		}
		static final EnumMap<SignParam, Object> initParameter(Map<SignParam, Object> formated){
			EnumMap<SignParam, Object> fullParam = defaultParameter();
			if(null != formated){
				fullParam.putAll(formated);
			}
			return fullParam;
		}
	}
	
	/**
	 * 格式化参数输出
	 * @param method
	 * @param thriftSignture
	 * @param param
	 * @return
	 */
	public String formateParam(Method method,LinkedHashMap<String, Type>thriftSignture,
			Map<String,Object>param){
		Map<String, Object> filtered = Maps.filterKeys(param, new Predicate<String>(){
			@Override
			public boolean apply(String input) {
				try{
					SignParam.valueOf(input);
					return true;
				}catch(Exception e){
					return false;
				}
			}});
		Map<SignParam, Object> fullParam = SignParam.initParameter(TransformUtils.transform(filtered, new Function<String,SignParam>(){
			@Override
			public SignParam apply(String input) {
				return SignParam.valueOf(input);
			}}));
		return formateParam(method,thriftSignture,
				(Boolean)fullParam.get(SignParam.isGeneric),
				(Boolean)fullParam.get(SignParam.withType),
				(Boolean)fullParam.get(SignParam.withName),
				(String)fullParam.get(SignParam.separator),
				(Boolean)fullParam.get(SignParam.rawTypeOnly),
				(Boolean)fullParam.get(SignParam.toRight), 
				(String) fullParam.get(SignParam.indent), 
				(Boolean)fullParam.get(SignParam.withFinal));
	}
}
